﻿#pragma once
/*
	⽇志器主要是⽤来和前端交互， 当我们需要使⽤⽇志系统打印log的时候， 只需要创建Logger对象，
调⽤该对象debug、info、warn、error、fatal等⽅法输出⾃⼰想打印的⽇志即可，⽀持解析可变参数
列表和输出格式， 即可以做到像使⽤printf函数⼀样打印⽇志。
	当前⽇志系统⽀持同步⽇志& 异步⽇志两种模式，两个不同的⽇志器唯⼀不同的地⽅在于他们在⽇志
的落地⽅式上有所不同：
	同步⽇志器：直接对⽇志消息进⾏输出。
	异步⽇志器：将⽇志消息放⼊缓冲区，由异步线程进⾏输出。
	因此⽇志器类在设计的时候先设计出⼀个Logger基类，在Logger基类的基础上，继承出SyncLogger同
步⽇志器和AsyncLogger异步⽇志器。
	且因为⽇志器模块是对前边多个模块的整合，想要创建⼀个⽇志器，需要设置⽇志器名称，设置⽇志
输出等级，设置⽇志器类型，设置⽇志输出格式，设置落地⽅向，且落地⽅向有可能存在多个，整个
⽇志器的创建过程较为复杂，为了保持良好的代码⻛格，编写出优雅的代码，因此⽇志器的创建这⾥
采⽤了建造者模式来进⾏创建。
*/

#define _GNU_SOURCE

#include "log_format.hpp"
#include "log_sink.hpp"
#include <mutex>
#include <atomic>
#include <cstdarg>

namespace Local_Log
{
	//日志器基类
	class Base_Logger
	{
	public:
		using ptr = std::shared_ptr<Base_Logger>;
		/*************构造析构************ */
		Base_Logger(const std::string loggername,
			Log_level::value level,
			Formatter::ptr formatter,
			std::vector<Base_Sink::ptr> sinks)
			:_loggername(loggername),
			_limitlevel(level),
			_formatter(formatter),
			_sinks(sinks.begin(), sinks.end())
		{
		}

		/*************成员函数************ */
		//完成构造日志消息对象过程，并进行格式化，得到格式化后的日志消息字符串，然后进行落地输出
		void Debug(const std::string& file, const size_t line, const std::string& fmt, ...)
		{
			//通过传入的参数构造出一个日志消息对象,进行最终的格式化，最终落地。
			//1.判断当前的日志是否达到了输出等级
			if (Log_level::value::DEBUG < _limitlevel) { return; }
			//2.对fmt参数和不定参组织，得到日志消息的字符串
			//1.定义 va_list 类型变量
			va_list lo_args;
			//2.获取起始变量->count之后的第一个参数
			va_start(lo_args, fmt.c_str());
			char lo_buf[1024];
			int lo_ret = _vsprintf_p(lo_buf, sizeof(lo_buf), fmt.c_str(), lo_args);
			//3.获得参数及类型，ap会自动偏移
			if (lo_ret == -1)
			{
				std::cout << "_vsprintf_p failed!\n";
				return;
			}
			//将ap指针置空
			va_end(lo_args);
			serialize(Log_level::value::DEBUG, file, line, lo_buf);
		}
		void Info(const std::string& file, size_t line, const std::string& fmt, ...)
		{
			//通过传入的参数构造出一个日志消息对象,进行最终的格式化，最终落地。
			//1.判断当前的日志是否达到了输出等级
			if (Log_level::value::INFO < _limitlevel) { return; }
			//2.对fmt参数和不定参组织，得到日志消息的字符串
			//1.定义 va_list 类型变量
			va_list lo_args;
			//2.获取起始变量->count之后的第一个参数
			va_start(lo_args, fmt.c_str());
			char lo_buf[1024];
			int lo_ret = _vsprintf_p(lo_buf, sizeof(lo_buf), fmt.c_str(), lo_args);
			//3.获得参数及类型，ap会自动偏移
			if (lo_ret == -1)
			{
				std::cout << "_vsprintf_p failed!\n";
				return;
			}
			//将ap指针置空
			va_end(lo_args);
			serialize(Log_level::value::INFO, file, line, lo_buf);
		}
		void Warning(const std::string& file, size_t line, const std::string& fmt, ...)
		{
			//通过传入的参数构造出一个日志消息对象,进行最终的格式化，最终落地。
			//1.判断当前的日志是否达到了输出等级
			if (Log_level::value::WARNING < _limitlevel) { return; }
			//2.对fmt参数和不定参组织，得到日志消息的字符串
			//1.定义 va_list 类型变量
			va_list lo_args;
			//2.获取起始变量->count之后的第一个参数
			va_start(lo_args, fmt.c_str());
			char lo_buf[1024];
			int lo_ret = _vsprintf_p(lo_buf, sizeof(lo_buf), fmt.c_str(), lo_args);
			//3.获得参数及类型，ap会自动偏移
			if (lo_ret == -1)
			{
				std::cout << "_vsprintf_p failed!\n";
				return;
			}
			//将ap指针置空
			va_end(lo_args);
			serialize(Log_level::value::WARNING, file, line, lo_buf);
		}
		void Lerror(const std::string& file, size_t line, const std::string& fmt, ...)
		{
			//通过传入的参数构造出一个日志消息对象,进行最终的格式化，最终落地。
			//1.判断当前的日志是否达到了输出等级
			if (Log_level::value::LERROR < _limitlevel) { return; }
			//2.对fmt参数和不定参组织，得到日志消息的字符串
			//1.定义 va_list 类型变量
			va_list lo_args;
			//2.获取起始变量->count之后的第一个参数
			va_start(lo_args, fmt.c_str());
			char lo_buf[1024];
			int lo_ret = _vsprintf_p(lo_buf, sizeof(lo_buf), fmt.c_str(), lo_args);
			//3.获得参数及类型，ap会自动偏移
			if (lo_ret == -1)
			{
				std::cout << "_vsprintf_p failed!\n";
				return;
			}
			//将ap指针置空
			va_end(lo_args);
			serialize(Log_level::value::LERROR, file, line, lo_buf);
		}
		void Falat(const std::string& file, size_t line, const std::string& fmt, ...)
		{
			//通过传入的参数构造出一个日志消息对象,进行最终的格式化，最终落地。
			//1.判断当前的日志是否达到了输出等级
			if (Log_level::value::FALAT < _limitlevel) { return; }
			//2.对fmt参数和不定参组织，得到日志消息的字符串
			//1.定义 va_list 类型变量
			va_list lo_args;
			//2.获取起始变量->count之后的第一个参数
			va_start(lo_args, fmt.c_str());
			char lo_buf[1024];
			int lo_ret = _vsprintf_p(lo_buf, sizeof(lo_buf), fmt.c_str(), lo_args);
			//3.获得参数及类型，ap会自动偏移
			if (lo_ret == -1)
			{
				std::cout << "_vsprintf_p failed!\n";
				return;
			}
			//将ap指针置空
			va_end(lo_args);
			serialize(Log_level::value::FALAT, file, line, lo_buf);
		}
	protected:
		void serialize(Log_level::value level, const std::string& file, const size_t line, const std::string& buf)
		{
			//3.构造Log_Msg对象
			Log_Msg lo_msg(level, line, file, _loggername, buf);
			//4.通过格式化工具对Log_Msg进行格式化，得到格式化后的日志字符串
			std::stringstream lo_ss;
			_formatter->StreamFormat(lo_ss, lo_msg);
			//5.进行日志落地
			Log(lo_ss.str().c_str(), lo_ss.str().size());
		}
		//抽象接口完成实际的落地输出，不同的日志器，会有不同的实际落地方式
		virtual void Log(const char* data, size_t len) = 0;
		virtual void Log(const std::string& data) = 0;
	protected:
		std::mutex _mutex;
		std::string _loggername;
		std::atomic<Log_level::value> _limitlevel;
		Formatter::ptr _formatter;
		std::vector<Base_Sink::ptr> _sinks;
	};
	//同步日志器
	class SyncLogger :public Base_Logger
	{
	public:
		/*************构造析构************ */
		SyncLogger(const std::string logger_name,
			Log_level::value level,
			Formatter::ptr formatter,
			std::vector<Base_Sink::ptr> sinks)
			:Base_Logger(logger_name,level,formatter,sinks)
		{
		}

		/*************成员函数************ */
	protected:
		//同步日志器，是将日志直接通过落地模块句柄进行日志落地
		void Log(const char* data, size_t len)override
		{
			std::unique_lock<std::mutex> lo_lock(_mutex);
			if (_sinks.empty())return;
			for (auto &it : _sinks)
			{
				it->Log(data,len);
			}
		}
		void Log(const std::string& data) override
		{
			std::unique_lock<std::mutex> lo_lock(_mutex);
			if (_sinks.empty())return;
			for (auto& it : _sinks)
			{
				it->Log(data);
			}
		}
	};
	//使用建造者模式来构造日志器，简化用户使用复杂度
	enum struct Logger_Type
	{
		LOGGER_SYNC,
		LOGGER_ASYNC
	};
	//1.抽象一个日志器建造者类(完成日志器所需要的零部件的构建，日志器的构建)
	//--1.设置日志器类型
	//--2.将不同的日志器创建放到同一个建造者类中
	class Base_LoggerBuider
	{
	public:
		Base_LoggerBuider():_loggertype(Logger_Type::LOGGER_SYNC), _limitlevel(Log_level::value::DEBUG){}
		void buiderloggertype(Logger_Type type) { _loggertype = type; }
		void buiderloggername(const std::string& name) { _loggername = name; }
		void buiderlimitlevel(Log_level::value level) { _limitlevel = level; }
		void buiderformatter(const std::string& pattern = "")
		{
			if (pattern == "")
				_formatter = std::make_shared<Formatter>();
			else
				_formatter = std::make_shared<Formatter>(pattern);
		}
		template<class SinkType, class ...Args>
		void buidersinks(Args &&...args)
		{
			Base_Sink::ptr psink = SinkFactory::CreateSink<SinkType>(std::forward<Args>(args)...);
			_sinks.emplace_back(psink);
		}
	public:
		virtual Base_Logger::ptr BuiderLogger() = 0;
	protected:
		Logger_Type _loggertype;
		std::string _loggername;
		Log_level::value _limitlevel;
		Formatter::ptr _formatter;
		std::vector<Base_Sink::ptr> _sinks;
	};
	//2.派生出具体的建造者类--局部日志器建造者 与 全局日志器建造者
	//--全局日志器建造者会添加全局单例和全局单例管理
	class Local_LoggerBuilder:public Base_LoggerBuider
	{
	public:
		Base_Logger::ptr BuiderLogger()override
		{
			assert(!_loggername.empty());
			if (_formatter.get()==nullptr)
			{
				_formatter = std::make_shared<Formatter>();
			}
			if (_sinks.empty())
			{
				buidersinks<StdoutSink>();
			}
			if (_loggertype == Logger_Type::LOGGER_ASYNC)
			{

			}
			return std::make_shared<SyncLogger>(_loggername, _limitlevel,_formatter,_sinks);

		}
	};

}


